// Copyright (c) 2023 刻BITTER
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.


#pragma once

#include <cstddef>
#include <cstdint>
#include <type_traits>

#ifndef _CAT

    #define _CAT(a, b)        a##b
    #define _CAT3(a, b, c)    a##b##c
    #define _CAT4(a, b, c, d) a##b##c##d

    #define _SUPER_CAT(a, b)        _CAT(a, b)
    #define _SUPER_CAT3(a, b, c)    _CAT3(a, b, c)
    #define _SUPER_CAT4(a, b, c, d) _CAT4(a, b, c, d)

#endif


#define _IOXX_ENUM_TO_UNDERLYING(e) static_cast<std::underlying_type_t<decltype(e)>>(e)

#define _IOXX_ENUM_TO_ENUM(e, to_type) static_cast<to_type>(static_cast<std::underlying_type_t<decltype(e)>>(e))


namespace ioxx {

    enum class cmd {
        disable = 0,
        enable = 1,
    };


    enum class polarity {
        high = 1,
        low = 0,
    };


    enum class level {
        high = 1,
        low = 0,
    };
    
    
    template <typename EnumType>
    constexpr auto _enum_to_underlying(EnumType e) {
        return static_cast<std::underlying_type_t<EnumType>>(e);
    }
    
    
    template <typename ToEnumType, typename EnumType>
    constexpr ToEnumType _enum_to_enum(EnumType e) {
        return static_cast<ToEnumType>(static_cast<std::underlying_type_t<EnumType>>(e));
    }


    template <typename EnumType>
    constexpr auto _calc_enum_underlying_sum(EnumType e) {
        return _IOXX_ENUM_TO_UNDERLYING(e);
    }


    template <typename EnumType, typename... Ts>
    constexpr auto _calc_enum_underlying_sum(EnumType e, Ts... args) {
        return _IOXX_ENUM_TO_UNDERLYING(e) | _calc_enum_underlying_sum(args...);
    }


    template <typename ReturnType>
    constexpr ReturnType _calc_bv_sum(unsigned int bit_position) {
        return static_cast<ReturnType>(1 << bit_position);
    }


    /**
     * @brief 相当于将多个_BV(bit_position) 或运算后返回
     *
     * @tparam ReturnType
     * @param bit_position
     * @return constexpr ReturnType
     */
    template <typename ReturnType, typename... Ts>
    constexpr ReturnType _calc_bv_sum(unsigned int bit_position, Ts... args) {
        return _calc_bv_sum<ReturnType>(bit_position) | _calc_bv_sum<ReturnType>(args...);
    }

}  // namespace ioxx